/*
 * Copyright 2007 Steven Blundy.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.caree


import scala.xml.{Document, Elem, Node, NodeSeq, Text}
import scala.{Option, Some, None}

import java.net.URL

trait SoapConnection {
  /** Sends a sequence of nodes to the end point
   * @param bodyElements A sequence of NodeSeq, each being the contents of a particular body element
   */
  def send(bodyElements: NodeSeq*): Response
}
/** 
 * Represents a connection to a particular SOAP service
 */
abstract class SoapConnectionImpl() extends SoapConnection {
  self: XmlTransmitter =>
  
  private val logger = org.apache.log4j.Logger.getLogger(classOf[SoapConnection])
  /** Sends a sequence of nodes to the end point
   * @param bodyElements A sequence of NodeSeq, each being the contents of a particular body element
   */
  def send(bodyElements: NodeSeq*): Response = {
    val msg = new Document() 
    msg.docElem = <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
                                xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">{
                                  bodyElements.map(body => <soapenv:Body>{body}</soapenv:Body>)
                                }</soapenv:Envelope>
    val rdoc = transmit(msg)

    return rdoc.docElem match {
      case e:Elem if("soapenv".equals(e.prefix) && "Envelope".equals(e.label)) => handleContents(e.child)
      case _ => { logger.error("No envelope:doc=" + rdoc); throw new SoapException("No Envelope") }
    }
  }

  private def handleContents(contents: Seq[Node]): Response = {
    val headers = contents takeWhile {child => child.label equals "Header" }
    val bodies = contents.drop(headers.size).takeWhile({child => child.label equals "Body" })

    return StandardResponse(handleHeaders(headers), handleBodies(bodies))
  }

  private def handleHeaders(headers: Seq[NodeSeq]): Seq[NodeSeq] = {
    return headers.map({ child => child \ "_" } )
  }

  private def handleBodies(bodies: Seq[NodeSeq]): Seq[NodeSeq] = {
    return bodies.map({ child => child \ "_" } )
  }
}

object SoapConnection {
  def createConnectionForUrl(endpointUrl: URL): Option[SoapConnection] = {
    return endpointUrl.getProtocol() match {
      case "http" => Some(new SoapConnectionImpl() with HttpXmlTransmitter { def url = endpointUrl })
      case _ => None
    }
  }
}

sealed class Response {}

case class StandardResponse(headers: Seq[NodeSeq], bodies: Seq[NodeSeq]) extends Response {}